#include <QDataStream>
#include <QFile>
#include <QSslKey>
#include <QSslConfiguration>

#include "Network/Manager.h"
#include <QTimer>

#include "../include/Constance.h"
#include <qDebug>
#include "Connection.h"

namespace TC
{
    namespace Network
    {
        Manager::Manager()
        {
            assert(_instance == nullptr);
            // #TODO: initialize class

            _instance = this;
        }

        Manager::~Manager()
        {
            _instance = nullptr;
        }

        Connection *Manager::get(const QString &command, const QVariantMap &args)
        {
            Connection *socket = createSocket();
            QByteArray sd;
            QDataStream stream(&sd, QIODevice::WriteOnly);
            stream << command << args;
            socket->write(sd);
            socket->flush();
            return socket;
        }

        QByteArray readAll(const char *path)
        {
            QFile f(path);
            f.open(QIODevice::ReadOnly);
            return f.readAll();
        }

        Connection * Manager::createSocket(QObject *parent /*= nullptr*/)
        {
            Connection *s = new Connection(parent);

            QSslConfiguration sslConfiguration;
            QFile keyFile(QStringLiteral(":/client.key"));
            keyFile.open(QIODevice::ReadOnly);
            QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
            keyFile.close();

            sslConfiguration.setCaCertificates(QSslCertificate::fromPath(":/ca.crt"));
            sslConfiguration.setLocalCertificateChain(QSslCertificate::fromPath(":/client.crt"));
            sslConfiguration.setPrivateKey(sslKey);
            sslConfiguration.setPeerVerifyMode(Connection::VerifyPeer);
            //sslConfiguration.setProtocol(QSsl::TlsV1_2);

            s->setSslConfiguration(sslConfiguration);
            s->connectToHostEncrypted(Constance::strings.server, Constance::numbers.port);
            QObject::connect(s, static_cast<void(Connection::*)(const QList<QSslError> &)>(&Connection::sslErrors), [=](const QList<QSslError> &errors)
            {
                qDebug() << errors << endl;
            });
            return s;
        }

        Manager* Manager::instance()
        {
            if (_instance == nullptr)
                _instance = new Manager;
            return _instance;
        }

        Manager* Manager::_instance = nullptr;
    }

}
